Skip to content

Always use CE_CACHE, remove TYPE_HAS_CE #7336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 11, 2021
Merged

Always use CE_CACHE, remove TYPE_HAS_CE #7336

merged 4 commits into from
Aug 11, 2021

Conversation

nikic
Copy link
Member

@nikic nikic commented Aug 3, 2021

Currently, CE_CACHE on strings is only used opcache interned strings. This patch extends usage to non-opcache interned strings as well. This means that most type strings can now make use of CE_CACHE even if opcache is not loaded, which allows us to remove TYPE_HAS_CE kind, and fix some discrepancies depending on whether a type stores a resolved or non-resolved name.

There are two cases where CE_CACHE will not be used:

  • When opcache is not used and a permanent interned string (that is not an internal class name) is used as a type name during the request. In this case we can't allocate a map_ptr index for the permanent string, as it would be not be in the permanent map_ptr index space.
  • When opcache is used but the script is not cached (e.g. eval'd code). If opcache is used, we can't allocate additional map_ptr indexes at runtime, because they may conflict with indexes allocated by opcache.

In these two cases we would end up not using CE caching for property types (argument/return types still have the separate cache slot).

@nikic nikic requested a review from dstogov August 3, 2021 12:48
Comment on lines 513 to 521
finish:
/* Transfer CE_CACHE map ptr slot to new interned string.
* Should only happen for permanent interned strings with permanent map_ptr slot. */
if (ZSTR_HAS_CE_CACHE(str)) {
ZEND_ASSERT(GC_FLAGS(str) & IS_STR_PERMANENT);
GC_SET_REFCOUNT(s, GC_REFCOUNT(str));
GC_ADD_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only necessary for calls from accel_copy_permanent_strings(). Right?

Copy link
Member Author

@nikic nikic Aug 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's the only place it can happen, though it shouldn't hurt to check for it in other cases either.

This is missing a && !ZSTR_HAS_CE_CACHE(s) check though -- no need to do this again if cache is already present.

Copy link
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but see comments.

After this patch run_time_cache for RECV and VERIFY_RETURN_TYPE make sense only for ''self'' and ''parent''. It would be great to remove it completely (not necessary as part of this PR)

Comment on lines +1876 to +1877
if (zend_string_equals_literal_ci(type_name, "self")
|| zend_string_equals_literal_ci(type_name, "parent")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may make sense to add self and parent into ZEND_KNOWN_STRINGS and compare just pointers.

Comment on lines +4134 to +4136
zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*single_type));
ZEND_TYPE_SET_PTR(*single_type, name);
zend_alloc_ce_cache(name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't allocate new cache slot for eval()'ed code when opcache active (or when opcache is full).

Comment on lines +1866 to +1870
if (ZSTR_HAS_CE_CACHE(type_name) || !ZSTR_IS_INTERNED(type_name)) {
return;
}

if ((GC_FLAGS(type_name) & IS_STR_PERMANENT) && startup_done) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means, that we won't allocate CE cache slots during requests if opcache active. Right?
This will affect eval()'ed code, opcache.blacklisted files and situation when opcache is full.

Copy link
Member Author

@nikic nikic Aug 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the key tradeoff with this patch. There are cases where we can't allocate CE_CACHE (eval with opcache, permanent strings during request without opcache), so property types will be uncached (arg types still have separate cache slot).

I didn't have any simple ideas on how to address this. One thought I had is that we could change the map_ptr mechanism to not work using "ptr or offset", but to have two different map_ptr_base for permanent and per-request and always use offset. That is *(map_ptr_base[ptr & 1] + ptr) as the access method. Per-request slots would then be allocated in the map_ptr area rather than on CG arena.

This would allow allocating new per-request slots without clashing with new permanent slots allocated by opcache. However, just that isn't enough as well, as with opcache there are no per-request interned strings at all, and we can't use the refcount as storage for non-interned strings.

Do you have any ideas?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible to grow map_ptr vector in both directions having the single biased base. e.g. positive offsets for permanent slots and negative for per-request slots. anyway, this is not for 8.1

Copy link
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the solution is good enough for 8.1.

For 8.2 we should think about 3-levels of interned strings, biased map_ptr vector and removing run-time cache for RECV/VERIFY_RETURN_TYPE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants